//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CRenderer9.cpp>
///	@path	~/src/graphics/dx9/
///	@date	2007/10/26
///	@desc	.

#include "config/config.h"

#include <set>
#include <map>

#include "lib/utilities/debug.h"
#include "lib/utilities/observer.h"
#include "lib/system/thread_debug.h"

#include "database/store/IFile.h"
#include "database/store/IFileSystem.h"

#include "graphics/DxHelpers.h"
#include "graphics/dx9/CRenderer9.h"
#include "graphics/dx9/CShadingPass9.h"
#include "graphics/dx9/CSimpleGeometry9.h"
#include "graphics/dx9/CFont9.h"
#include "graphics/dx9/CSprite9.h"
#include "graphics/dx9/CEffect9.h"
#include "graphics/dx9/CTechnique9.h"
#include "graphics/dx9/CEffectPool9.h"
#include "graphics/dx9/CEffectCompiled9.h"
#include "graphics/dx9/CShaderAdapter9.h"
#include "graphics/dx9/CRenderState9.h"
#include "graphics/dx9/CTexture2D9.h"
#include "graphics/dx9/COffscreenRenderTarget9.h"
#include "graphics/dx9/CColorRenderTarget9.h"
#include "graphics/dx9/CDepthRenderTarget9.h"
#include "graphics/dx9/CRenderTargetSet9.h"
#include "graphics/dx9/CBlendState9.h"
#include "graphics/dx9/CVertexLayout9.h"
#include "graphics/dx9/CConstantVertex9.h"
#include "graphics/dx9/CDynamicVertex9.h"
#include "graphics/dx9/CConstantIndex9.h"
#include "graphics/dx9/CDynamicIndex9.h"

TRACE_CATEGORY( _S("Graphics/DX9/renderer") , TRACE_LV_TRACE );

namespace xeres {

	IMPL_IOBJECT_CLASS_DYNAMIC( CRenderer9 );

	// ctor
	CRenderer9::CRenderer9( void )
		: m_freeSlot( 0 )
		, m_checkIter( 0 )
	{
	}

	// dtor
	CRenderer9::~CRenderer9( void )
	{
	}

	class CDefaultRenderTarget9 : public IRenderTarget
	{
	public:

		/// \ctor
		CDefaultRenderTarget9( IDirect3DSurface9 * surface )
			: m_surface( surface )
		{
			HRESULT hr = m_surface->GetDesc( &m_desc );
			XS_ASSERT( SUCCEEDED(hr) );
		}

		/// \dtor
		virtual ~CDefaultRenderTarget9( void )
		{
			if( m_surface )
			{
				m_surface->Release();
				m_surface = NULL;
			}
		}

		DECL_IOBJECT_CLASS( CDefaultRenderTarget9 , IRenderTarget );

		/// \impl
		virtual bool OnLostDevice( void )
		{
			if( m_surface )
			{
				m_surface->Release();
				m_surface = NULL;
			}
			return true;
		}

		/// \impl
		virtual bool OnResetDevice( RefWeak<IDevice> device )
		{
			RefWeak<CDevice9> d3d9 = device;
			HRESULT hr = d3d9->GetDevice()->GetRenderTarget( 0 , &m_surface );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CDefaultRenderTarget9::OnResetDevice: Failed to get default render target: %s") , d3d_get_err(hr) );
				return false;
			}
			hr = m_surface->GetDesc( &m_desc );
			XS_ASSERT( SUCCEEDED(hr) );
			return true;
		}

		/// \brief	Apply render target to primary stage.
		virtual bool ApplyTarget( RefWeak<IDevice> device )
		{
			RefWeak<CDevice9> d3d9 = device;
			HRESULT hr = d3d9->GetDevice()->SetRenderTarget( 0 , m_surface );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CDefaultRenderTarget9::Apply: Failed to set render target: %s.") , d3d_get_err(hr) );
				return false;
			}
			return true;
		}

		/// \impl
		virtual TextureType GetType( void )
		{
			return TEXTURE_2D;
		}

		/// \impl
		virtual DXFormat GetFormat( void )
		{
			return m_desc.Format;
		}

		/// \impl
		virtual Pair<int> GetSize( void )
		{
			return Pair<int>( m_desc.Width , m_desc.Height );
		}

		/// \impl
		virtual size_t GetDepth( void )
		{
			FATAL_ABORT( _S("Try to get depth from 2D texture.") );
			return 0;
		}

		/// \impl
		virtual bool IsWritable( void )
		{
			return false;
		}

		/// \impl
		virtual bool IsReadable( void )
		{
			return false;
		}

		/// \impl
		virtual bool Map( uint sub , ResourceMap& data )
		{
			return false;
		}

		/// \impl
		virtual bool ReadBack( uint sub , ResourceMap& data , bool readonly )
		{
			return false;
		}

		/// \impl
		virtual bool Unmap( uint sub )
		{
			return false;
		}

		/// \impl
		virtual bool Update( uint sub , const Box<uint>& size , const byte * data , uint row_pitch , uint depth_pitch )
		{
			return false;
		}

		/// \impl
		virtual IUnknown * GetTextureInterface( void )
		{
			return NULL;
		}

		/// \impl
		virtual IUnknown * GetRenderTargetInterface( void )
		{
			return m_surface;
		}

	protected:

		IDirect3DSurface9 *		m_surface;
		D3DSURFACE_DESC			m_desc;
	};

	IMPL_IOBJECT_CLASS( CDefaultRenderTarget9 );

	class CDefaultDepthStencil9 : public CDefaultRenderTarget9
	{
	public:

		/// \ctor
		CDefaultDepthStencil9( IDirect3DSurface9 * surface )
			: CDefaultRenderTarget9( surface )
		{

		}

		DECL_IOBJECT_CLASS( CDefaultDepthStencil9 , CDefaultRenderTarget9 );

		/// \impl
		virtual bool OnResetDevice( RefWeak<IDevice> device )
		{
			RefWeak<CDevice9> d3d9 = device;
			HRESULT hr = d3d9->GetDevice()->GetDepthStencilSurface( &m_surface );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CDefaultDepthStencil9::OnResetDevice: Failed to get default render target: %s") , d3d_get_err(hr) );
				return false;
			}
			hr = m_surface->GetDesc( &m_desc );
			XS_ASSERT( SUCCEEDED(hr) );
			return true;
		}

		/// \brief	Apply render target to primary stage.
		virtual bool ApplyTarget( RefWeak<IDevice> device )
		{
			RefWeak<CDevice9> d3d9 = device;
			HRESULT hr = d3d9->GetDevice()->SetDepthStencilSurface( m_surface );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CDefaultRenderTarget9::Apply: Failed to set render target: %s.") , d3d_get_err(hr) );
				return false;
			}
			return true;
		}

		/// \impl
		virtual TextureType GetType( void )
		{
			return TEXTURE_DEPTH;
		}
	};

	IMPL_IOBJECT_CLASS( CDefaultDepthStencil9 );

	// initialize
	void CRenderer9::Initialize( RefWeak<IDevice> device , RefWeak<IData> config )
	{
		// function only runs on main thread
		RUNNING_ON_THREAD( _S("main") );

		if( !device->IsA<CDevice9>() )
		{
			TRACE_ERROR( _S("CRenderer9::Initialize: Device API version mismatch.") );
			FATAL_ABORT( _S("Device API version mismatch.") );
		}

		m_device = device;

		m_device->AttachCallback( this );

		RefWeak<CDevice9> d3d9 = device;

		IDirect3DSurface9 * pSurface = NULL;
		d3d9->GetDevice()->GetRenderTarget( 0 , &pSurface );
		m_defaultRenderTarget = new CDefaultRenderTarget9( pSurface );
		d3d9->GetDevice()->GetDepthStencilSurface( &pSurface );
		m_defaultDepthStencil = new CDefaultDepthStencil9( pSurface );

		AddResource( m_defaultRenderTarget );
		AddResource( m_defaultDepthStencil );

		SetEffectDefinition( "_D3D9" , "1" );
		SetEffectDefinition( "D3D9" , "1" );
	}

	// finalize
	void CRenderer9::Finalize( void )
	{
		// function only runs on main thread
		RUNNING_ON_THREAD( _S("main") );

		m_includes.clear();
		m_defines.clear();
		m_resouces.clear();
		m_cachedLayout.clear();
		m_defaultPool = NULL;
		m_defaultRenderTarget = NULL;
		m_defaultDepthStencil = NULL;
		m_defaultRenderState = NULL;
		m_freeSlot = 0;
		m_device = NULL;
	}

	// GetColorOrder
	ColorOrder CRenderer9::GetColorOrder( void ) const
	{
		return COLOR_ORDER_ARGB;
	}

	// GetDevice
	RefWeak<IDevice> CRenderer9::GetDevice( void )
	{
		return m_device;
	}

	void CRenderer9::Tick( const Frame& frame )
	{
		COUNTER_GUARD( _S("overhead") );

		// every frame check 1 resource.
		if( m_checkIter > m_resouces.size() )
		{
			m_checkIter = 0;
		}
		else
		{
			if( m_resouces[m_checkIter].IsValid() && m_resouces[m_checkIter]->IsUniqueRef() )
			{
				m_resouces[m_checkIter] = NULL;
				++m_freeSlot;
			}
			++m_checkIter;
		}

	}

	bool CRenderer9::PreChangeMode( RefWeak<IDevice> device , void * oldSettings , void * newSettings )
	{
		return true;
	}

	bool CRenderer9::PostChangeMode( RefWeak<IDevice> device , void * settings )
	{
		return true;
	}

	bool CRenderer9::OnLostDevice( RefWeak<IDevice> device )
	{
		for( size_t i = 0 , total = m_resouces.size() ; i < total ; ++i )
		{
			if( m_resouces[i].IsValid() )
			{
				if( !m_resouces[i]->OnLostDevice() )
				{
					TRACE_ERROR( _S("CRenderer9::OnLostDevice: Resource failed to reset." ) );
					FATAL_ABORT( _S("Failed to reset resource.") );
				}
			}
		}
		return true;
	}

	bool CRenderer9::OnResetDevice( RefWeak<IDevice> device )
	{
		for( size_t i = 0 , total = m_resouces.size() ; i < total ; ++i )
		{
			if( m_resouces[i].IsValid() )
			{
				if( !m_resouces[i]->OnResetDevice( device ) )
				{
					TRACE_ERROR( _S("CRenderer9::OnResetDevice: Resource failed to reset." ) );
					FATAL_ABORT( _S("Failed to reset resource.") );
				}
			}
		}
		RestoreDefaultState();
		return true;
	}

	// OnResizingSwapchain
	bool CRenderer9::OnResizingSwapchain( RefWeak<IDevice> device )
	{
		return true;
	}

	// OnResizedSwapchain
	bool CRenderer9::OnResizedSwapchain( RefWeak<IDevice> device )
	{
		return true;
	}
	
	bool CRenderer9::OnDestroyDevice( RefWeak<IDevice> device )
	{
		return true;
	}

	void CRenderer9::FreeDeviceResource( RefWeak<IDeviceResource> resource )
	{
		for( size_t i = 0 , total = m_resouces.size() ; i < total ; ++i )
		{
			if( m_resouces[i] == resource )
			{
				m_resouces[i] = NULL;
				++m_freeSlot;
				return;
			}
		}
		TRACE_ERROR( _S("CRenderer9::FreeDeviceResource: Cannot find given resource to free.") );
	}

	// DefaultShadingPass
	RefPass<IPass> CRenderer9::DefaultShadingPass( void )
	{
		return new CShadingPass9;
	}

	namespace
	{
		// Available semantic in DX9.

		class _SemanticMap
		{
		public:

			/// \instance
			static _SemanticMap& instance( void )
			{
				static _SemanticMap s_semanticMap_instance;
				return s_semanticMap_instance;
			}

			/// \brief	Translate semantic.
			std::pair<D3DDECLUSAGE,int> TranslateSemantic( const char * semantic )
			{
				dict< AString,std::pair<D3DDECLUSAGE,int> >::iterator it = m_semantic.find( semantic );
				if( it == m_semantic.end() )
				{
					return std::make_pair( D3DDECLUSAGE(-1) , -1 );
				}
				return it->second;
			}

		private:

			/// \ctor
			_SemanticMap( void )
			{
				m_semantic[("POSITION")] = std::make_pair( D3DDECLUSAGE_POSITION , 0 );
				m_semantic[("BLENDWEIGHT")] = std::make_pair( D3DDECLUSAGE_BLENDWEIGHT , 0 );
				m_semantic[("BLENDINDICES")] = std::make_pair( D3DDECLUSAGE_BLENDINDICES , 0 );
				m_semantic[("NORMAL")] = std::make_pair( D3DDECLUSAGE_NORMAL , 0 );
				m_semantic[("PSIZE")] = std::make_pair( D3DDECLUSAGE_PSIZE , 0 );
				m_semantic[("TEXCOORD")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 0 );
				m_semantic[("TANGENT")] = std::make_pair( D3DDECLUSAGE_TANGENT , 0 );
				m_semantic[("BINORMAL")] = std::make_pair( D3DDECLUSAGE_BINORMAL , 0 );
				m_semantic[("TESSFACTOR")] = std::make_pair( D3DDECLUSAGE_TESSFACTOR , 0 );
				m_semantic[("POSITIONT")] = std::make_pair( D3DDECLUSAGE_POSITIONT , 0 );
				m_semantic[("COLOR")] = std::make_pair( D3DDECLUSAGE_COLOR , 0 );
				m_semantic[("COLOR0")] = std::make_pair( D3DDECLUSAGE_COLOR , 0 );
				m_semantic[("COLOR1")] = std::make_pair( D3DDECLUSAGE_COLOR , 1 );
				m_semantic[("FOG")] = std::make_pair( D3DDECLUSAGE_FOG , 0 );
				m_semantic[("DEPTH")] = std::make_pair( D3DDECLUSAGE_DEPTH , 0 );

				m_semantic[("DIFFUSE")] = std::make_pair( D3DDECLUSAGE_COLOR , 0 );
				m_semantic[("SPECULAR")] = std::make_pair( D3DDECLUSAGE_COLOR , 1 );

				m_semantic[("TEXCOORD0")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 0 );
				m_semantic[("TEXCOORD1")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 1 );
				m_semantic[("TEXCOORD2")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 2 );
				m_semantic[("TEXCOORD3")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 3 );
				m_semantic[("TEXCOORD4")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 4 );
				m_semantic[("TEXCOORD5")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 5 );
				m_semantic[("TEXCOORD6")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 6 );
				m_semantic[("TEXCOORD7")] = std::make_pair( D3DDECLUSAGE_TEXCOORD , 7 );
			}

			// @data
			dict< AString,std::pair<D3DDECLUSAGE,int> >	m_semantic;
		};

		// Type converter mapping.

		class _TypeMap
		{
		public:

			typedef std::pair<D3DDECLTYPE,size_t> _TypeInfo;

			/// \instance
			static _TypeMap& instance( void )
			{
				static _TypeMap s_TypeMap_instance;
				return s_TypeMap_instance;
			}

			/// \brief	Get type info.
			const _TypeInfo& GetTypeInfo( VertexSlotType type )
			{
				XS_ASSERT( type >= 0 && type < VertexSlotType_last );
				return m_types[type];
			}

		private:

			/// \ctor
			_TypeMap( void )
			{
				m_types[VertexSlotType_Float1]		= _TypeInfo( D3DDECLTYPE_FLOAT1 , sizeof(float)*1 );
				m_types[VertexSlotType_Float2]		= _TypeInfo( D3DDECLTYPE_FLOAT2 , sizeof(float)*2 );
				m_types[VertexSlotType_Float3]		= _TypeInfo( D3DDECLTYPE_FLOAT3 , sizeof(float)*3 );
				m_types[VertexSlotType_Float4]		= _TypeInfo( D3DDECLTYPE_FLOAT4 , sizeof(float)*4 );
				m_types[VertexSlotType_Byte4]		= _TypeInfo( D3DDECLTYPE_UBYTE4 , sizeof(byte)*4 );
				m_types[VertexSlotType_Byte4Norm]	= _TypeInfo( D3DDECLTYPE_UBYTE4N , sizeof(byte)*4 );
				m_types[VertexSlotType_Short2] 		= _TypeInfo( D3DDECLTYPE_SHORT2 , sizeof(short)*2 );
				m_types[VertexSlotType_Short2Norm] 	= _TypeInfo( D3DDECLTYPE_SHORT2N , sizeof(short)*2 );
				m_types[VertexSlotType_Short4] 		= _TypeInfo( D3DDECLTYPE_SHORT4 , sizeof(short)*4 );
				m_types[VertexSlotType_Short4Norm] 	= _TypeInfo( D3DDECLTYPE_SHORT4N , sizeof(short)*4 );
				m_types[VertexSlotType_UShort2Norm] = _TypeInfo( D3DDECLTYPE_USHORT2N , sizeof(short)*2 );
				m_types[VertexSlotType_UShort4Norm] = _TypeInfo( D3DDECLTYPE_USHORT4N , sizeof(short)*4 );
				m_types[VertexSlotType_Half2] 		= _TypeInfo( D3DDECLTYPE_FLOAT16_2 , sizeof(short)*2 );
				m_types[VertexSlotType_Half4] 		= _TypeInfo( D3DDECLTYPE_FLOAT16_4 , sizeof(short)*4 );
				// color
				m_types[VertexSlotType_ColorRGBA] 	= _TypeInfo( D3DDECLTYPE_D3DCOLOR , sizeof(byte)*4 );
				m_types[VertexSlotType_ColorfRGBA] 	= _TypeInfo( D3DDECLTYPE_FLOAT4 , sizeof(float)*4 );
			}

			// @data
			std::map<VertexSlotType,_TypeInfo>	m_types;
		};

		// Vertex declaration converter.

		class _DeclConverter
		{
		public:

			/// \ctor
			_DeclConverter( const std::vector<VertexSlotDeclaration>& decl )
				: m_size( 0 )
				, m_slot( 0 )
				, m_decl( decl )
			{
				m_decl9.resize( decl.size() + 1 );
				for( size_t i = 0 , total = decl.size() ; i < total ; ++i )
				{
					D3DVERTEXELEMENT9 * e9 = &m_decl9[i];
					memset( e9 , 0 , sizeof(D3DVERTEXELEMENT9) );
				}
				//make an end
				static const D3DVERTEXELEMENT9 s_end = {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0};
				m_decl9[ decl.size() ] = s_end;
			}

			// resolve
			bool resolve( void )
			{
				for( size_t i = 0 , total = m_decl.size() ; i < total ; ++i )
				{
					// see if new slot committed
					if( m_slot != m_decl[i].slot )
					{
						XS_ASSERT( m_slot < m_decl[i].slot );
						// new slot, end current
						push_slot( i );
					}

					// convert
					if( !convert_entry( i ) )
						return false;
				}
				if( !m_currentLayout.empty() )
					push_slot( m_decl.size() - 1 );

				return true;
			}

			// push slot
			void push_slot( size_t index )
			{
				// new slot, end current
				Ref<CSlotLayout> slot = new CSlotLayout( m_size , m_currentLayout );
				m_slots.push_back( slot );
				m_size = 0;
				m_slot = m_decl[index].slot;
				m_currentLayout.clear();
			}

			size_t m_size , m_slot;
			const std::vector<VertexSlotDeclaration>& m_decl;
			std::vector<D3DVERTEXELEMENT9> m_decl9;
			std::vector< VertSlotDecl > m_currentLayout;
			std::vector< Ref<CSlotLayout> > m_slots;

		private:

			// convert entry
			bool convert_entry( size_t index )
			{
				const VertexSlotDeclaration& decl = m_decl[index];
				D3DVERTEXELEMENT9& dve9 = m_decl9[index];
				size_t input_size = 0 , output_size = 0;
				std::pair<D3DDECLUSAGE,int> usage = _SemanticMap::instance().TranslateSemantic( decl.semantic );
				if( usage.first == -1 && usage.second == -1 )
				{
					TRACE_ERROR( _S("CRenderer9::DeclareVertexLayout: Invalid semantic for DirectX 9 '%S'.") , decl.semantic );
					return false;
				}
				XS_ASSERT( decl.offset <= m_size );
				const _TypeMap::_TypeInfo& info = _TypeMap::instance().GetTypeInfo( decl.type );
				dve9.Stream = decl.slot;
				dve9.Offset = decl.offset;
				dve9.Type = info.first;
				dve9.Method = D3DDECLMETHOD_DEFAULT;
				dve9.Usage = usage.first;
				dve9.UsageIndex = usage.second;

				VertSlotDecl slot_decl;
				slot_decl.offset = decl.offset;
				slot_decl.size = info.second;
				m_currentLayout.push_back( slot_decl );
				m_size += slot_decl.size;

				return true;
			}
		};
	}

	namespace
	{
		/// \brief	Make shader with specific declaration.
		void MakeDefaultShader( AString& code , const std::vector<D3DVERTEXELEMENT9>& decl )
		{
			bool has_position = false;
			bool has_position_t = false;
			bool has_color = false;
			AString position_name;
			AString color_name;
			AString TransformPosition( "TransformPosition4" );
			char buf[64];

			code = "/* CRenderer9 Generated Default Shader */\n\n#include \"standard_fx.fxh\"\n\n";

			// Make input structure
			AString input_struct( "\nstruct VERTEX_IN{\n" );
			AString output_struct( "\nstruct VERTEX_OUT{\n" );
			for( size_t i = 0 , total = decl.size() - 1 ; i < total ; ++i )
			{
				const D3DVERTEXELEMENT9& desc = decl[i];
				const char * type = d3d_vertex_to_hlsl_type( (D3DDECLTYPE)desc.Type );
				const char * semantic = d3d_usage_to_semantic( (D3DDECLUSAGE)desc.Usage , desc.UsageIndex );
				if( desc.Usage == D3DDECLUSAGE_POSITIONT && desc.UsageIndex == 0 )
					semantic = "POSITION";

				sprintf( buf , "param_%u" , i );
				input_struct += "\t";
				input_struct += type;
				input_struct += "\t";
				input_struct += buf;
				input_struct += " : ";
				input_struct += semantic;
				input_struct += ";\n";

				if( desc.Usage == D3DDECLUSAGE_COLOR && desc.UsageIndex == 0 )
				{
					has_color = true;
					color_name = buf;
				}
				else if( desc.Usage == D3DDECLUSAGE_POSITION && desc.UsageIndex == 0 )
				{
					has_position = true;
					position_name = buf;
					if( strcmp( type , "float3" ) == 0 )
					{
						TransformPosition = "TransformPosition3";
						type = "float4";
					}
				}
				else if( desc.Usage == D3DDECLUSAGE_POSITIONT && desc.UsageIndex == 0 )
				{
					has_position_t = true;
					position_name = buf;
					type = "float4";
				}
				else
				{
					// dont' write output.
					continue;
				}

				output_struct += "\t";
				output_struct += type;
				output_struct += "\t";
				output_struct += buf;
				output_struct += " : ";
				output_struct += semantic;
				output_struct += ";\n";
			}
			input_struct += "};\n\n";
			output_struct += "};\n\n";

			code += input_struct;
			code += output_struct;

			// vertex shader
			code += "VERTEX_OUT DefaultVS( VERTEX_IN input ) {\n\tVERTEX_OUT output;\n";
			if( has_color )
			{
				code += "\toutput." + color_name + "= input." + color_name + ";\n";
			}
			if( has_position_t )
			{
				// transformed position
				code += "\toutput." + position_name + "= input." + position_name + ";\n";
			}
			else
			{
				// needs transform
				code += "\toutput." + position_name + "=" + TransformPosition + "(input." + position_name + ");\n";
			}
			code += "\treturn output;\n}\n";

			code += "float4 DefaultPS( VERTEX_OUT input ) : COLOR {\n";
 
			if( has_color )
			{
				code += "\treturn input." + color_name + ";\n}\n";
			}
			else
			{
				code += "\treturn float4(1,1,1,1);\n}\n";
			}

			code += "technique DefaultMaterial{\n"
				"\tpass p0{\n"
				"\t\tAlphaBlendEnable = True;\n\t\tSeparateAlphaBlendEnable = False;\n"
				"\t\tSrcBlend = SRCALPHA;\n\t\tDestBlend = INVSRCALPHA;\n\t\tBlendOp = ADD;\n"
				"\t\tVertexShader = compile vs_2_0 DefaultVS();\n"
				"\t\tPixelShader = compile ps_2_0 DefaultPS();\n"
				"\t}\n}\n";
		}
	}

	// DeclareVertexLayout
	RefPass<IVertexLayout> CRenderer9::DeclareVertexLayout( const std::vector<VertexSlotDeclaration>& decl )
	{
		if( decl.empty() || decl.size() >= MAXD3DDECLLENGTH )
		{
			TRACE_ERROR( _S("CRenderer9::DeclareVertexLayout: Invalid declaration count.") );
			return NULL;
		}
		// sort declaration
		//std::sort( decl.begin() , decl.end() , VertexSlotDeclaration::SortDecl() );

		AString signature = VertexSlotDeclaration::make_signature( decl );
		dict< AString , Ref<IVertexLayout> >::iterator it = m_cachedLayout.find( signature );
		if( it != m_cachedLayout.end() )
			return it->second;

		// try to convert declaration to dx9 decl.
		
		_DeclConverter converter( decl );
		if( !converter.resolve() )
		{
			return NULL;
		}
		
		IDirect3DVertexDeclaration9 * pDecl9 = NULL;
		HRESULT hr = m_device->GetDevice()->CreateVertexDeclaration( &converter.m_decl9.front() , &pDecl9 );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::DeclareVertexLayout: Failed to create vertex declaration: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}

		AString code;
		MakeDefaultShader( code , converter.m_decl9 );

		Ref<IEffect> effect = CreateEffect( code.c_str() , code.size() , m_defaultPool );
		Ref<ITechnique> technique = effect->GetTechnique( "DefaultMaterial" );
		Ref<CShaderAdapter9> adapter = new CShaderAdapter9( technique );
		Ref<IVertexLayout> retval = new CVertexLayout9( adapter , pDecl9 , converter.m_slots );
		m_cachedLayout[signature] = retval;
		return retval;
	}

	// create dynamic vertex
	RefPass<IVertexBuffer> CRenderer9::CreateDynamicVertex( RefWeak<ISlotLayout> layout , size_t vertex_count ,
		const void * init_data , size_t size )
	{
		size_t stride = layout->GetLayoutSize();
		size_t total_size = stride * vertex_count;

		// FIXME ! Should create a resource provider instead of raw data
		IDirect3DVertexBuffer9 * pVertexBuffer = NULL;
		HRESULT hr = (*m_device)->CreateVertexBuffer(
			(UINT)total_size , D3DUSAGE_WRITEONLY , 0 , D3DPOOL_MANAGED , &pVertexBuffer , 0 );
		if( FAILED( hr ) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateDynamicVertex: Failed to create vertex buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}
		if( init_data )
		{
			XS_ASSERT( total_size == size );
			// copy buffer
			void * pData = NULL;
			hr = pVertexBuffer->Lock( 0 , 0 , &pData , D3DLOCK_DISCARD );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CRenderer9::CreateDynamicVertex: Failed to lock vertex buffer: %s") ,
					d3d_get_err( hr ) );
				return NULL;
			}

			memcpy( pData , init_data , size );
			pVertexBuffer->Unlock();
		}
		CDynamicVertex9 * vertex = new CDynamicVertex9( pVertexBuffer , vertex_count , stride );
		return RefPass<IVertexBuffer>( vertex );
	}

	// create immutable vertex
	RefPass<IVertexBuffer> CRenderer9::CreateConstantVertex( RefWeak<ISlotLayout> layout , size_t vertex_count ,
		const void * init_data , size_t size )
	{
		size_t stride = layout->GetLayoutSize();
		size_t total_size = stride * vertex_count;
		XS_ASSERT( total_size == size );
		XS_ASSERT( init_data );

		// FIXME ! Should create a resource provider instead of raw data
		IDirect3DVertexBuffer9 * pVertexBuffer = NULL;
		HRESULT hr = (*m_device)->CreateVertexBuffer(
			(UINT)total_size , D3DUSAGE_WRITEONLY , 0 , D3DPOOL_MANAGED , &pVertexBuffer , 0 );
		if( FAILED( hr ) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateConstantVertex: Failed to create vertex buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}
		// copy buffer
		void * pData = NULL;
		hr = pVertexBuffer->Lock( 0 , 0 , &pData , 0 );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateConstantVertex: Failed to lock vertex buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}

		memcpy( pData , init_data , size );
		pVertexBuffer->Unlock();

		CConstantVertex9 * vertex = new CConstantVertex9( pVertexBuffer , vertex_count , stride );
		return RefPass<IVertexBuffer>( vertex );
	}

	// CreateDynamicIndex
	RefPass<IVertexIndex> CRenderer9::CreateDynamicIndex( size_t count , size_t size , const void * init_data )
	{
		D3DFORMAT format = D3DFMT_FORCE_DWORD;
		if( size / count == sizeof(short) )
		{
			format = D3DFMT_INDEX16;
		}
		else if( size / count == sizeof(int32) )
		{
			format = D3DFMT_INDEX32;
		}
		else
		{
			TRACE_ERROR( _S("CRenderer9::CreateDynamicIndex: Size of index mismatch, per index size must be 16bit or 32bit." ) );
			return NULL;
		}
		// FIXME ! Should create a resource provider instead of raw data
		IDirect3DIndexBuffer9 * pIndexBuffer = NULL;
		HRESULT hr = (*m_device)->CreateIndexBuffer(
			(UINT)size , D3DUSAGE_WRITEONLY , format , D3DPOOL_MANAGED , &pIndexBuffer , 0 );
		if( FAILED( hr ) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateDynamicIndex: Failed to create index buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}
		if( init_data )
		{
			// copy buffer
			void * pData = NULL;
			hr = pIndexBuffer->Lock( 0 , 0 , &pData , D3DLOCK_DISCARD );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CRenderer9::CreateDynamicIndex: Failed to lock index buffer: %s") ,
					d3d_get_err( hr ) );
				return NULL;
			}

			memcpy( pData , init_data , size );
			pIndexBuffer->Unlock();
		}
		CDynamicIndex9 * index = new CDynamicIndex9( pIndexBuffer , count );
		return RefPass<IVertexIndex>( index );
	}

	// CreateConstantIndex
	RefPass<IVertexIndex> CRenderer9::CreateConstantIndex( size_t count , size_t size , const void * init_data )
	{
		XS_ASSERT( init_data );

		D3DFORMAT format = D3DFMT_FORCE_DWORD;
		if( size / count == sizeof(short) )
		{
			format = D3DFMT_INDEX16;
		}
		else if( size / count == sizeof(int32) )
		{
			format = D3DFMT_INDEX32;
		}
		else
		{
			TRACE_ERROR( _S("CRenderer9::CreateConstantIndex: Size of index mismatch, per index size must be 16bit or 32bit." ) );
			return NULL;
		}
		// FIXME ! Should create a resource provider instead of raw data
		IDirect3DIndexBuffer9 * pIndexBuffer = NULL;
		HRESULT hr = (*m_device)->CreateIndexBuffer(
			(UINT)size , D3DUSAGE_WRITEONLY , format , D3DPOOL_MANAGED , &pIndexBuffer , 0 );
		if( FAILED( hr ) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateConstantIndex: Failed to create index buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}
		if( init_data )
		{
			// copy buffer
			void * pData = NULL;
			hr = pIndexBuffer->Lock( 0 , 0 , &pData , 0 );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CRenderer9::CreateConstantIndex: Failed to lock index buffer: %s") ,
					d3d_get_err( hr ) );
				return NULL;
			}

			memcpy( pData , init_data , size );
			pIndexBuffer->Unlock();
		}
		CConstantIndex9 * index = new CConstantIndex9( pIndexBuffer , count );
		return RefPass<IVertexIndex>( index );
	}

	// create simple geometry
	RefPass<IGeometry> CRenderer9::CreateSimplePolygon(
		TopologyType type ,
		RefWeak<IVertexLayout> layout ,
		size_t vertex_count ,
		const void * vertex_data ,
		size_t index_count ,
		const ushort * index_data )
	{
		TRACK_FUNCTION_SCOPE();

		RefWeak<ISlotLayout> slot = layout->GetSlot( 0 );
		size_t stride = slot->GetLayoutSize();

		size_t vertex_total = vertex_count * stride;
		size_t index_total = index_count * sizeof(ushort);
		
		// check geometry type
		D3DPRIMITIVETYPE prim_type = d3d_topology_type9( type );
		size_t count = d3d_prim_count( type , vertex_count , index_count );

		if( prim_type == D3DPT_FORCE_DWORD )
		{
			TRACE_ERROR( _S("CRenderer9::CreateSimplePolygon: Adjacency is not supported in DX9.") );
			return NULL;
		}

		IDirect3DVertexBuffer9 * pVertexBuffer = NULL;
		IDirect3DIndexBuffer9 * pIndexBuffer = NULL;

		HRESULT hr = (*m_device)->CreateVertexBuffer(
			(UINT)vertex_total , 0 , 0 , D3DPOOL_MANAGED , &pVertexBuffer , 0 );

		if( FAILED( hr ) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateSimplePolygon: Failed to create vertex buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}

		if( index_count )
		{
			hr = (*m_device)->CreateIndexBuffer(
				(UINT)( index_count * sizeof(ushort) ) , 0 , D3DFMT_INDEX16 , D3DPOOL_MANAGED , &pIndexBuffer , 0 );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CRenderer9::CreateSimplePolygon: Failed to create index buffer: %s") ,
					d3d_get_err( hr ) );
				return NULL;
			}
		}

		// copy buffer
		void * pData = NULL;
		hr = pVertexBuffer->Lock( 0 , 0 , &pData , 0 );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateSimplePolygon: Failed to lock vertex buffer: %s") ,
				d3d_get_err( hr ) );
			return NULL;
		}

		memcpy( pData , vertex_data , vertex_total );

		if( pIndexBuffer )
		{
			hr = pIndexBuffer->Lock( 0 , 0 , &pData , 0 );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CRenderer9::CreateSimplePolygon: Failed to lock index buffer: %s") ,
					d3d_get_err( hr ) );
				return NULL;
			}
			memcpy( pData , index_data , index_total );
		}

		pVertexBuffer->Unlock();

		if( pIndexBuffer )
			pIndexBuffer->Unlock();

		CSimpleGeometry9 * retval = new CSimpleGeometry9( stride , count , prim_type , layout , pVertexBuffer , pIndexBuffer );
		return RefPass<IGeometry>( retval );
	}

	// create geometry from vertices
	RefPass<IGeometry> CRenderer9::CreateGeometry(
		TopologyType type ,
		std::vector< RefWeak<IVertexBuffer> >& vertices )
	{
		return NULL;
	}

	// add resource
	void CRenderer9::AddResource( RefWeak<IDeviceResource> res )
	{
		// add new resource to list
		if( m_freeSlot == 0 )
		{
			m_resouces.push_back( res );
		}
		else
		{
			--m_freeSlot;
			for( size_t i = 0 , total = m_resouces.size() ; i < total ; ++i )
			{
				if( m_resouces[i].IsNull() )
				{
					m_resouces[i] = res;
					break;
				}
			}
		}
	}

	RefPass<IFont> CRenderer9::CreateFont( const WString& faceName ,
			int height , int width , int weight , bool italic , bool highQuality , bool scalable )
	{
		IDirect3DDevice9 * device = m_device->GetDevice();

		ID3DXFont * font = NULL;
		HRESULT hr = dx9::D3DXCreateFont(
			device ,
			height , width , weight ,
			scalable ? D3DX_DEFAULT : 1 ,
			italic ,
			DEFAULT_CHARSET ,
			OUT_DEFAULT_PRECIS ,
			highQuality ? CLEARTYPE_NATURAL_QUALITY : DEFAULT_QUALITY ,
			DEFAULT_PITCH | FF_DONTCARE ,
			faceName.c_str() , &font );

		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateFont: Failed to create font <%s>: %s") , faceName.c_str() ,
				d3d_get_err(hr) );
			return NULL;
		}

		CFont9 * font9 = new CFont9( font );
		AddResource( font9 );
		return RefPass<IFont>( font9 );
	}

	RefPass<ISprite> CRenderer9::CreateSprite( void )
	{
		IDirect3DDevice9 * device = m_device->GetDevice();

		ID3DXSprite * sprite = NULL;
		HRESULT hr = dx9::D3DXCreateSprite( device , &sprite );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateSprite: Failed to create sprite: %s") , d3d_get_err(hr) );
			return NULL;
		}

		CSprite9 * sprite9 = new CSprite9( sprite );
		AddResource( sprite9 );
		return RefPass<ISprite>( sprite9 );
	}

	// CreateTextureForSprite
	RefPass<ITexture> CRenderer9::CreateTextureForSprite( int width , int height )
	{
		// create 2d texture

		// create rgba format texture, for sprite rendering

		IDirect3DTexture9 * pTexture = NULL;

		HRESULT hr = (*m_device)->CreateTexture( width , height , 1 ,
			0 , D3DFMT_A8R8G8B8 , D3DPOOL_MANAGED ,
			&pTexture , NULL );

		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateTextureForSprite: Failed to create texture: %s") , d3d_get_err(hr) );
			return NULL;
		}

		CTexture2D9 * tex = new CTexture2D9( pTexture );

		// Don't need to release while reset device because we use managed pool.
		return RefPass<ITexture>(tex);
	}
	
	// CreateColorRenderTarget
	RefPass<IRenderTarget> CRenderer9::CreateColorRenderTarget( int width , int height )
	{
		// create 2d render target
		IDirect3DTexture9 * pTexture = NULL;
		
		HRESULT hr = (*m_device)->CreateTexture( width , height , 1 , D3DUSAGE_RENDERTARGET ,
			D3DFMT_A8R8G8B8 , D3DPOOL_DEFAULT , &pTexture , NULL );

		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateColorRenderTarget: Failed to create render target: %s") , d3d_get_err(hr) );
			return NULL;
		}

		Ref<CColorRenderTarget9> target = new CColorRenderTarget9( pTexture );
		AddResource( target );
		return RefPass<IRenderTarget>( target );
	}

	// CreateRenderTargetSet
	RefPass<IRenderTargetSet> CRenderer9::CreateRenderTargetSet( int width , int height )
	{
		// just create
		Ref<CRenderTargetSet9> targets = new CRenderTargetSet9( width , height );
		return targets;
	}

	void CRenderer9::SetEffectDefinition( const AString& name , const AString& def )
	{
		m_defines[ name ] = def;
	}

	void CRenderer9::AddInclude( RefWeak<IFileSystem> filesystem , const WString& path )
	{
		WString fullpath( path );
		normalize_slash( fullpath.begin() , fullpath.end() , '/' );
		for( size_t i = 0 , total = m_includes.size() ; i < total ; ++i )
		{
			if( m_includes[i].m_fs == filesystem && m_includes[i].m_path == fullpath )
			{
				TRACE_WARNING( _S("CRenderer9::AddInclude: Include path has been defined <%s>.") , path.c_str() );
				return;
			}
		}
		_IncludeDir dir;
		dir.m_fs = filesystem;
		dir.m_path = fullpath;
		m_includes.push_back( dir );
	}

	void CRenderer9::DelInclude( RefWeak<IFileSystem> filesystem , const WString& path )
	{
		WString fullpath( path );
		normalize_slash( fullpath.begin() , fullpath.end() , '/' );
		for( size_t i = 0 , total = m_includes.size() ; i < total ; ++i )
		{
			if( m_includes[i].m_fs == filesystem && m_includes[i].m_path == fullpath )
			{
				m_includes.erase( m_includes.begin() + i );
				return;
			}
		}
		TRACE_WARNING( _S("CRenderer9::DelInclude: Include path has been deleted <%s>.") , path.c_str() );
	}

	namespace
	{
		// implementation of include class
		class _CDXInclude9 : public ID3DXInclude
		{
		public:

			//@ ctor
			_CDXInclude9( std::vector< CRenderer9::_IncludeDir >& pathes )
				: m_includes( pathes )
			{
			}

			//@ dtor
			~_CDXInclude9( void )
			{
				ClearCache();
			}

			// Clear cache
			void ClearCache( void )
			{
				if( m_data.size() > 0 )
				{
					TRACE_WARNING( _S("_CDXInclude9::ClearCache: Include file cache is not all freed.") );

					for( std::set<void*>::iterator it = m_data.begin() , end = m_data.end() ;
						it != end ; ++it )
					{
						free( (*it) );
					}
				}
			}

			// A user-implemented method for opening and reading the contents of a shader #include file.
			virtual HRESULT __stdcall Open(
				D3DXINCLUDE_TYPE IncludeType , LPCSTR pFileName , LPCVOID pParentData,
				LPCVOID * ppData , UINT * pBytes )
			{
				*ppData = NULL;
				*pBytes = 0;

				WString wFileName;
				mbs_to_wcs( pFileName , wFileName );

				// resolve input file name
				Ref<IFile> file;
				for( size_t i = 0 , total = m_includes.size() ; i < total ; ++i )
				{
					CRenderer9::_IncludeDir& dir = m_includes[i];
					file = dir.m_fs->OpenFile( dir.m_path + WString( L"/" ) + wFileName );
					if( file.IsValid() )
						break;
				}
				
				if( file.IsNull() )
				{
					TRACE_ERROR( _S("CRenderer9: Failed to open include file for effect compile <%s>") , wFileName.c_str() );
					return E_FAIL;
				}

				// read file
				DataInfo info;
				file->GetInfo( info );
				DWORD size = (DWORD)info.m_size , readSize = 0;
				void * data = malloc( size );
				readSize = (DWORD)file->Read( data , size );
				assert( size == readSize );

				*ppData = data;
				*pBytes = size;
				
				m_data.insert( data );

				return S_OK;
			}

			// A user-implemented method for closing a shader #include file.
			virtual HRESULT __stdcall Close( LPCVOID pData )
			{
				std::set<void *>::iterator it = m_data.find( (void*)pData );
				assert( it != m_data.end() );
				m_data.erase( it );
				free( (void*)pData );
				return S_OK;
			}

		private:

		//@ data

			std::vector< CRenderer9::_IncludeDir >	m_includes;
			std::set<void *>						m_data;
		};
	}

	RefPass<IEffect> CRenderer9::CreateEffect( const void * buffer , size_t len , RefWeak<IEffectPool> pool )
	{
		TRACK_FUNCTION_SCOPE();

		HRESULT hr = S_OK;

		IDirect3DDevice9 * device = m_device->GetDevice();
		ID3DXEffectPool * pPool = NULL;
		if( pool.IsValid() )
		{
			IUnknown * inter = pool->GetEffectPoolInterface();
			hr = inter->QueryInterface( IID_ID3DXEffectPool , (void**)&pPool );
			XS_ASSERT( SUCCEEDED(hr) );
		}

		// prepare compilation

		ID3DXEffect * effect = NULL;
		ID3DXBuffer * error = NULL;

		// create defines
		D3DXMACRO * macro = static_cast<D3DXMACRO*>( alloca( sizeof(D3DXMACRO) * ( m_defines.size() + 1 ) ) );
		int count = 0;
		for( dict<AString,AString>::iterator it = m_defines.begin() , end = m_defines.end() ;
			it != end ; ++it , ++count )
		{
			macro[count].Name = it->first.c_str();
			macro[count].Definition = it->second.c_str();
		}
		macro[count].Name = NULL;
		macro[count].Definition = NULL;

		// create includes
		_CDXInclude9 includes( m_includes );

		// make compile flags
		DWORD flags = 0;

		hr = dx9::D3DXCreateEffect(
			device , buffer , (UINT)len , macro , &includes , flags ,
			pPool , &effect , &error );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateEffect: Failed to create effect: %S") ,
				error->GetBufferPointer() );
			XS_VERIFY( error->Release() == 0 );
			return NULL;
		}

		if( error )
		{
			XS_VERIFY( error->Release() == 0 );
			error = NULL;
		}

		// create effect
		CEffect9 * retval = new CEffect9( effect , pool );
		AddResource( retval );
		return RefPass< IEffect >( retval );
	}

	// CreateEffectPool
	RefPass<IEffectPool> CRenderer9::CreateEffectPool( const char * buffer , size_t len )
	{
		TRACK_FUNCTION_SCOPE();

		IDirect3DDevice9 * device = m_device->GetDevice();
		ID3DXEffectPool * pool = NULL;
		HRESULT hr = dx9::D3DXCreateEffectPool( &pool );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateEffectPool: Failed to create effect pool: %s.") ,
				d3d_get_err(hr) );
			return NULL;
		}

		// create master effect
		AString code( buffer );
		code += "\n"
			"float4 DefaultVS( float4 Position:POSITIONT ): POSITIONT {\n"
				"\treturn Position; }\n"
			"float4 DefaultPS( float4 Position:POSITIONT ) : COLOR {\n"
				"\treturn float4(1,1,1,1);\n}"
			"technique PoolTechnique {\n\tpass p0{\n"
				"\tVertexShader = compile vs_2_0 DefaultVS();\n"
				"\tPixelShader = compile ps_2_0 DefaultPS();\n"
			"\t}\n}\n";

		// compile shader
		ID3DXEffect * effect = NULL;
		ID3DXBuffer * error = NULL;

		// create defines
		D3DXMACRO * macro = static_cast<D3DXMACRO*>( alloca( sizeof(D3DXMACRO) * ( m_defines.size() + 1 ) ) );
		int count = 0;
		for( dict<AString,AString>::iterator it = m_defines.begin() , end = m_defines.end() ;
			it != end ; ++it , ++count )
		{
			macro[count].Name = it->first.c_str();
			macro[count].Definition = it->second.c_str();
		}
		macro[count].Name = NULL;
		macro[count].Definition = NULL;

		// create includes
		_CDXInclude9 includes( m_includes );

		// make compile flags
		DWORD flags = 0;

		hr = dx9::D3DXCreateEffect(
			device , buffer , (UINT)len , macro , &includes , flags ,
			pool , &effect , &error );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateEffectPool: Failed to create master effect: %S") ,
				error->GetBufferPointer() );
			XS_VERIFY( error->Release() == 0 );
			return NULL;
		}

		if( error )
		{
			XS_VERIFY( error->Release() == 0 );
			error = NULL;
		}
		CEffectPool9 * retval = new CEffectPool9( effect , pool );
		return RefPass<IEffectPool>( retval );
	}

	RefPass<IEffectCompiled> CRenderer9::CompileEffect( const char * src , size_t len , RefWeak<IEffectPool> pool )
	{
		TRACK_FUNCTION_SCOPE();

		// make compiler
		ID3DXEffectCompiler * compiler = NULL;
		ID3DXBuffer * compiled = NULL;
		ID3DXBuffer * error = NULL;

		HRESULT hr = S_OK;

		// create defines
		D3DXMACRO * macro = static_cast<D3DXMACRO*>( alloca( sizeof(D3DXMACRO) * ( m_defines.size() + 1 ) ) );
		int count = 0;
		for( dict<AString,AString>::iterator it = m_defines.begin() , end = m_defines.end() ;
			it != end ; ++it , ++count )
		{
			macro[count].Name = it->first.c_str();
			macro[count].Definition = it->second.c_str();
		}
		macro[count].Name = NULL;
		macro[count].Definition = NULL;

		// create includes
		_CDXInclude9 includes( m_includes );

		// make compile flags
		DWORD flags = 0;

		hr = dx9::D3DXCreateEffectCompiler( src , (UINT)len ,
			macro , &includes , flags , &compiler , &error );

		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CompileEffect: Failed to create compiler: %s") ,
				error->GetBufferPointer() );
			XS_VERIFY( error->Release() == 0 );
			return NULL;
		}

		if( error )
		{
			XS_VERIFY( error->Release() == 0 );
			error = NULL;
		}

		// make shader flags
		DWORD shader_flags = 0;

		hr = compiler->CompileEffect( shader_flags , &compiled , &error );

		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CompileEffect: Failed to create compiler: %s.") ,
				error->GetBufferPointer() );
			XS_VERIFY( error->Release() == 0 );
			return NULL;
		}

		if( error )
		{
			XS_VERIFY( error->Release() == 0 );
			error = NULL;
		}

		// create effect
		RefPass<IEffect> effect = CreateEffect(
			compiled->GetBufferPointer() , compiled->GetBufferSize() , pool );

		if( effect.IsNull() )
			return NULL;

		CEffectCompiled9 * retval = new CEffectCompiled9( RefWeak<IEffect>(effect) , compiled );
		return RefPass<IEffectCompiled>( retval );
	}

	// LinkEffect
	RefPass<IShaderAdapter> CRenderer9::LinkEffect( RefWeak<ITechnique> technique , RefWeak<IVertexLayout> layout )
	{
		return new CShaderAdapter9( technique );
	}

	// GetDefaultRenderTarget
	RefWeak<IRenderTarget> CRenderer9::GetDefaultRenderTarget( void )
	{
		return m_defaultRenderTarget;
	}

	// GetDefaultDepthStencil
	RefWeak<IRenderTarget> CRenderer9::GetDefaultDepthStencil( void )
	{
		return m_defaultDepthStencil;
	}

	// RestoreDefaultRenderTarget
	void CRenderer9::RestoreDefaultRenderTarget( void )
	{
		m_defaultRenderTarget->ApplyTarget( m_device );
	}

	// RestoreDefaultDepthStencil
	void CRenderer9::RestoreDefaultDepthStencil( void )
	{
		m_defaultDepthStencil->ApplyTarget( m_device );
	}
	// CreateStateForAll
	RefPass<IRenderState> CRenderer9::CreateStateForAll( void )
	{
		IDirect3DStateBlock9 * block = NULL;
		HRESULT hr = m_device->GetDevice()->CreateStateBlock( D3DSBT_ALL , &block );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::CreateStateForAll: Failed to create render state: %s") , d3d_get_err(hr) );
			return NULL;
		}
		CRenderState9 * state = new CRenderState9( block , D3DSBT_ALL );
		AddResource( state );
		return RefPass<IRenderState>( state );
	}
	// SetTexture
	bool CRenderer9::SetTexture( int shader_type , int sampler , RefWeak<ITexture> texture )
	{
		IDirect3DTexture9 * tex = NULL;
		if( texture.IsValid() )
		{
			texture->GetTextureInterface()->QueryInterface( IID_IDirect3DTexture9 , (void**)&tex );
			if( tex == NULL )
			{
				TRACE_ERROR( _S("CRenderer9::SetTexture: Invalid texture type to set: %s") ,
					texture->GetClassName().c_str() );
				return false;
			}
		}
		HRESULT hr = m_device->GetDevice()->SetTexture( sampler , tex );
		if( tex )
			tex->Release();
		tex = NULL;
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CRenderer9::SetTexture: Failed to set texture: %s") , d3d_get_err(hr) );
			return false;
		}
		return true;
	}
	// CreateBlendState
	RefPass<IBlendState> CRenderer9::CreateBlendState( BlendSet& blend )
	{
		return RefPass<IBlendState>( new CBlendState9( blend ) );
	}
	// RestoreDefaultState
	void CRenderer9::RestoreDefaultState( void )
	{
		IDirect3DDevice9 * d9 = m_device->GetDevice();

		D3DXMATRIXA16 mat;
		D3DXMatrixIdentity( &mat );
		d9->SetTransform( D3DTS_VIEW , &mat );
		d9->SetTransform( D3DTS_PROJECTION , &mat );
		d9->SetTransform( D3DTS_TEXTURE0 , &mat );
		d9->SetTransform( D3DTS_TEXTURE1 , &mat );
		d9->SetTransform( D3DTS_TEXTURE2 , &mat );
		d9->SetTransform( D3DTS_TEXTURE3 , &mat );
		d9->SetTransform( D3DTS_TEXTURE4 , &mat );
		d9->SetTransform( D3DTS_TEXTURE5 , &mat );
		d9->SetTransform( D3DTS_TEXTURE6 , &mat );
		d9->SetTransform( D3DTS_TEXTURE7 , &mat );
		d9->SetTransform( D3DTS_WORLD , &mat );
		d9->SetTransform( D3DTS_WORLD1 , &mat );
		d9->SetTransform( D3DTS_WORLD2 , &mat );
		d9->SetTransform( D3DTS_WORLD3 , &mat );

		d9->SetFVF(0);
		d9->SetVertexShader( NULL );
		d9->SetPixelShader( NULL );

		if( m_defaultRenderState.IsNull() )
		{
			m_defaultRenderState = CreateStateForAll();
		}
		if( m_defaultRenderState->RequireCapture() )
		{
			float one = 1.0f;
			float _64 = 64.0f;

			d9->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
			d9->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
			d9->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
			d9->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
			d9->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
			d9->SetRenderState( D3DRS_LASTPIXEL, TRUE );
			d9->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
			d9->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
			d9->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
			d9->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
			d9->SetRenderState( D3DRS_ALPHAREF, 0 );
			d9->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_ALWAYS );
			d9->SetRenderState( D3DRS_DITHERENABLE, FALSE );
			d9->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
			d9->SetRenderState( D3DRS_FOGENABLE, FALSE );
			d9->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
			d9->SetRenderState( D3DRS_FOGCOLOR, 0 );
			d9->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
			d9->SetRenderState( D3DRS_FOGSTART, 0 );
			d9->SetRenderState( D3DRS_FOGEND, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_FOGDENSITY, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_RANGEFOGENABLE, FALSE );
			d9->SetRenderState( D3DRS_STENCILENABLE, FALSE );
			d9->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
			d9->SetRenderState( D3DRS_STENCILREF, 0 );
			d9->SetRenderState( D3DRS_STENCILMASK, 0xFFFFFFFF );
			d9->SetRenderState( D3DRS_STENCILWRITEMASK, 0xFFFFFFFF );
			d9->SetRenderState( D3DRS_TEXTUREFACTOR, 0xFFFFFFFF );
			d9->SetRenderState( D3DRS_WRAP0, 0 );
			d9->SetRenderState( D3DRS_WRAP1, 0 );
			d9->SetRenderState( D3DRS_WRAP2, 0 );
			d9->SetRenderState( D3DRS_WRAP3, 0 );
			d9->SetRenderState( D3DRS_WRAP4, 0 );
			d9->SetRenderState( D3DRS_WRAP5, 0 );
			d9->SetRenderState( D3DRS_WRAP6, 0 );
			d9->SetRenderState( D3DRS_WRAP7, 0 );
			d9->SetRenderState( D3DRS_CLIPPING, TRUE );
			d9->SetRenderState( D3DRS_LIGHTING, TRUE );
			d9->SetRenderState( D3DRS_AMBIENT, 0 );
			d9->SetRenderState( D3DRS_FOGVERTEXMODE, D3DFOG_NONE );
			d9->SetRenderState( D3DRS_COLORVERTEX, TRUE );
			d9->SetRenderState( D3DRS_LOCALVIEWER, TRUE );
			d9->SetRenderState( D3DRS_NORMALIZENORMALS, FALSE );
			d9->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1 );
			d9->SetRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2 );
			d9->SetRenderState( D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL );
			d9->SetRenderState( D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL );
			d9->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
			d9->SetRenderState( D3DRS_CLIPPLANEENABLE, 0 );
			d9->SetRenderState( D3DRS_POINTSIZE, *(DWORD*)&_64 );
			d9->SetRenderState( D3DRS_POINTSIZE_MIN, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
			d9->SetRenderState( D3DRS_POINTSCALEENABLE, FALSE );
			d9->SetRenderState( D3DRS_POINTSCALE_A, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_POINTSCALE_B, 0 );
			d9->SetRenderState( D3DRS_POINTSCALE_C, 0 );
			d9->SetRenderState( D3DRS_MULTISAMPLEANTIALIAS, TRUE );
			d9->SetRenderState( D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF );
			d9->SetRenderState( D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE );
			d9->SetRenderState( D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE );
			d9->SetRenderState( D3DRS_POINTSIZE_MAX, *(DWORD*)&_64 );
			d9->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
			d9->SetRenderState( D3DRS_COLORWRITEENABLE, 0x0000000F );
			d9->SetRenderState( D3DRS_TWEENFACTOR, 0 );
			d9->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD );
			d9->SetRenderState( D3DRS_POSITIONDEGREE, D3DDEGREE_CUBIC );
			d9->SetRenderState( D3DRS_NORMALDEGREE, D3DDEGREE_LINEAR );
			d9->SetRenderState( D3DRS_SCISSORTESTENABLE, FALSE );
			d9->SetRenderState( D3DRS_SLOPESCALEDEPTHBIAS, 0 );
			d9->SetRenderState( D3DRS_ANTIALIASEDLINEENABLE, FALSE );
			d9->SetRenderState( D3DRS_MINTESSELLATIONLEVEL, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_MAXTESSELLATIONLEVEL, *(DWORD*)&one );
			d9->SetRenderState( D3DRS_ADAPTIVETESS_X, 0 );
			d9->SetRenderState( D3DRS_ADAPTIVETESS_Y, 0 );
			d9->SetRenderState( D3DRS_ADAPTIVETESS_Z, 0 );
			d9->SetRenderState( D3DRS_ADAPTIVETESS_W, 0 );
			d9->SetRenderState( D3DRS_ENABLEADAPTIVETESSELLATION, FALSE );
			d9->SetRenderState( D3DRS_TWOSIDEDSTENCILMODE, FALSE );
			d9->SetRenderState( D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP );
			d9->SetRenderState( D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS );
			d9->SetRenderState( D3DRS_COLORWRITEENABLE1, 0x0000000F );
			d9->SetRenderState( D3DRS_COLORWRITEENABLE2, 0x0000000F );
			d9->SetRenderState( D3DRS_COLORWRITEENABLE3, 0x0000000F );
			d9->SetRenderState( D3DRS_BLENDFACTOR, 0xFFFFFFFF );
			d9->SetRenderState( D3DRS_SRGBWRITEENABLE, 0 );
			d9->SetRenderState( D3DRS_DEPTHBIAS, 0 );
			d9->SetRenderState( D3DRS_WRAP8, 0 );
			d9->SetRenderState( D3DRS_WRAP9, 0 );
			d9->SetRenderState( D3DRS_WRAP10, 0 );
			d9->SetRenderState( D3DRS_WRAP11, 0 );
			d9->SetRenderState( D3DRS_WRAP12, 0 );
			d9->SetRenderState( D3DRS_WRAP13, 0 );
			d9->SetRenderState( D3DRS_WRAP14, 0 );
			d9->SetRenderState( D3DRS_WRAP15, 0 );
			d9->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE );
			d9->SetRenderState( D3DRS_SRCBLENDALPHA, D3DBLEND_ONE );
			d9->SetRenderState( D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO );
			d9->SetRenderState( D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD );

			for( uint i = 0 ; i < m_device->GetCaps().MaxSimultaneousTextures ; ++i )
			{
				d9->SetSamplerState( i , D3DSAMP_ADDRESSU , D3DTADDRESS_WRAP );
				d9->SetSamplerState( i , D3DSAMP_ADDRESSV , D3DTADDRESS_WRAP );
				d9->SetSamplerState( i , D3DSAMP_ADDRESSW , D3DTADDRESS_WRAP );
				d9->SetSamplerState( i , D3DSAMP_BORDERCOLOR , 0x00000000 );
				d9->SetSamplerState( i , D3DSAMP_MAGFILTER , D3DTEXF_POINT );
				d9->SetSamplerState( i , D3DSAMP_MINFILTER , D3DTEXF_POINT );
				d9->SetSamplerState( i , D3DSAMP_MIPFILTER , D3DTEXF_NONE );
				d9->SetSamplerState( i , D3DSAMP_MIPMAPLODBIAS , 0 );
				d9->SetSamplerState( i , D3DSAMP_MAXMIPLEVEL , 0 );
				d9->SetSamplerState( i , D3DSAMP_MAXANISOTROPY , 1 );
				d9->SetSamplerState( i , D3DSAMP_SRGBTEXTURE , 0 );
				d9->SetSamplerState( i , D3DSAMP_ELEMENTINDEX , 0 );
				d9->SetSamplerState( i , D3DSAMP_DMAPOFFSET , 0 );

				d9->SetTextureStageState( i , D3DTSS_COLOROP , D3DTOP_DISABLE );
				d9->SetTextureStageState( i , D3DTSS_COLORARG1 , D3DTA_TEXTURE );
				d9->SetTextureStageState( i , D3DTSS_COLORARG2 , D3DTA_CURRENT );
				d9->SetTextureStageState( i , D3DTSS_ALPHAOP , D3DTOP_DISABLE );
				d9->SetTextureStageState( i , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE );
				d9->SetTextureStageState( i , D3DTSS_ALPHAARG2 , D3DTA_CURRENT );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVMAT00 , 0 );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVMAT01 , 0 );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVMAT10 , 0 );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVMAT11 , 0 );
				d9->SetTextureStageState( i , D3DTSS_TEXCOORDINDEX , 0 );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVLSCALE , 0 );
				d9->SetTextureStageState( i , D3DTSS_BUMPENVLOFFSET , 0 );
				d9->SetTextureStageState( i , D3DTSS_TEXTURETRANSFORMFLAGS , D3DTTFF_DISABLE );
				d9->SetTextureStageState( i , D3DTSS_COLORARG0 , D3DTA_CURRENT );
				d9->SetTextureStageState( i , D3DTSS_ALPHAARG0 , D3DTA_CURRENT );
				d9->SetTextureStageState( i , D3DTSS_RESULTARG , D3DTA_CURRENT );
				d9->SetTextureStageState( i , D3DTSS_CONSTANT , 0 );

				d9->SetTexture( i , NULL );
			}

			for( uint i = 0 ; i < m_device->GetCaps().MaxStreams ; ++i )
			{
				d9->SetStreamSource( i , NULL , 0 , 0 );
			}

			for( uint i = 1 ; i < m_device->GetCaps().NumSimultaneousRTs ; ++i )
			{
				d9->SetRenderTarget( i , NULL );
			}

			m_defaultRenderState->Capture();
		}
		else
		{
			m_defaultRenderState->Apply();
		}
	}
	// SetDefaultPool
	void CRenderer9::SetDefaultPool( const AString& shader )
	{
		RefPass<IEffectPool> pool = CreateEffectPool( shader.c_str() , shader.size() );
		if( pool.IsValid() )
		{
			m_defaultPool = pool;
		}
	}
	// GetDefaultEffectPool
	RefWeak<IEffectPool> CRenderer9::GetDefaultEffectPool( void )
	{
		return m_defaultPool;
	}
	// AddDeviceResource
	void CRenderer9::AddDeviceResource( RefWeak<IDeviceResource> res )
	{
		AddResource( res );
	}

} // namespace xeres
